#-*-coding:UTF-8-*-

import os.path
import types
import threading
import traceback
import functools

import tornado
import tornado.web
import tornado.websocket

import session as session
import urlfunc as urlfunc

try:
    import urlparse  # py2
except ImportError:
    import urllib.parse as urlparse  # py3

try:
    from urllib import urlencode  # py2
except ImportError:
    from urllib.parse import urlencode  # py3


from .props import (URL_PREFIX, APP_PREFIX, LOCAL_HTML_BASE, HTML_URL_BASE, 
                    HOME_URL, LOGIN_URL, NOT_FOUND_URL, ERROR_URL)
from ..logger import logger
from ..config import get_property, PLATMGT_HOME
from ..security.auth import check_userpass, get_login_user_info, is_user_admin

#TEMPLATE_PATH = os.path.join(os.path.split(os.path.split(os.path.split(os.path.abspath(__file__))[0])[0])[0], 'templates')



#_LOCAL_HTML_TEMP_PATH    = os.path.join(PLATMGT_HOME, 'templates', APP_PREFIX.strip('/'), 'pages', 'template.html')

#_LOCAL_HTML_NOFOUND_PATH = os.path.join(PLATMGT_HOME, 'templates', APP_PREFIX.strip('/'), 'pages', '404.html')


def authenticated(method):
    """Decorate methods with this to require that the user be logged in.

    If the user is not logged in, they will be redirected to the configured
    `login url <RequestHandler.get_login_url>`.

    If you configure a login url with a query parameter, Tornado will
    assume you know what you're doing and use it as-is.  If not, it
    will add a `next` parameter so the login page knows where to send
    you once you're logged in.
    """
    @functools.wraps(method)
    def wrapper(self, *args, **kwargs):
        if not self.current_user and self.request.path != LOGIN_URL:
            if self.request.method in ("GET", "HEAD"):
                url = self.get_login_url()
                if "?" not in url:
                    if urlparse.urlsplit(url).scheme:
                        # if login url is absolute, make next absolute too
                        next_url = self.request.full_url()
                    else:
                        next_url = self.request.uri
                    url += "?" + urlencode(dict(next=next_url))
                self.redirect(url)
                return
            raise HTTPError(403)
        return method(self, *args, **kwargs)
    return wrapper


class RequestHandlerEx(tornado.web.RequestHandler):

    def __init__(self,*args,**kwargs):
        super(RequestHandlerEx,self).__init__(*args,**kwargs)
        logger.debug('RequestHandlerEx init, thread info %s'%threading.current_thread())
        self._session = session.get_session(self)
        #self.prefix = APP_PREFIX.strip('/')

    def print_request_info(self):
        logger.debug('RequestHandlerEx.print_request_info start')
        logger.debug('cookies    = %s'%self.cookies)
        logger.debug('xsrf_token = %s'%self.xsrf_token)
        logger.debug('cookie of TORNADOSESSIONID : ')
        logger.debug(self.get_secure_cookie('TORNADOSESSIONID'))
        logger.debug('RequestHandlerEx.print_request_info  end')

    def get_current_user(self):
        if hasattr(self,'_session') and self._session.get_username():
            return self._session.get_username()
        return

    def get_session(self):
        return self._session

    def post(self,*args,**kwargs):
        return self.get(*args, **kwargs)


class NotFoundHandler(RequestHandlerEx):

    #@authenticated
    def get(self,*args,**kwargs):
        logger.debug('Page not found (NotFoundHandler) :%s'%self.request.uri)
        self.redirect(NOT_FOUND_URL)


class HomeHandler(RequestHandlerEx):

    def get(self, *args, **kwargs):
        logger.debug('HomeHandler.get request.path = %s'%self.request.path)
        self.redirect(HOME_URL)


class StaticFileHandlerEx(tornado.web.StaticFileHandler):

    def validate_absolute_path(self, root, absolute_path):
        try:
            return super(StaticFileHandlerEx, self).validate_absolute_path(root, absolute_path)
        except tornado.web.HTTPError as e:
            logger.debug('Page not found (StaticFileHandlerEx) : %s'%self.request.uri)
            self.redirect(NOT_FOUND_URL)
            return 


class DynamicPageHandler(RequestHandlerEx):
    '''
    process all *.html requests.
    for example: xyz/abc.html, it will call html_xyz_abc(handler) and return a dict

    '''
    #@tornado.web.authenticated
    def get(self, *args, **kwargs):
        self.process_get_and_post_request('get', *args, **kwargs)

    #@tornado.web.authenticated
    def post(self, *args, **kwargs):
        self.process_get_and_post_request('post', *args, **kwargs)

    def process_exception(self):
        '''prepare dict for rendering on page when getting exception
        usage: return self.process_exception()
        '''
        traceback.print_exc()
        #request_handler.get_session().set_attribute('exception',  traceback.format_exc().split('\n'))
        #request_handler.get_session().set_attribute('stacktrace', traceback.format_stack())
        error_file_path = os.path.join(LOCAL_HTML_BASE, 'error.html')
        render_dict = {}
        render_dict['HTML_URL_BASE'] = HTML_URL_BASE
        #render_dict['IS_ADMIN'] = is_user_admin(self.get_session().get_userid())
        render_dict['exc_lines'] = traceback.format_exc().split('\n')
        render_dict['stack_lines'] = traceback.format_stack()
        self.render(error_file_path, **render_dict)

    def process_no_found(self):
        logger.debug('DynamicPageHandler url not found: %s'%self.request.path)
        no_found_file_path = os.path.join(LOCAL_HTML_BASE, '404.html')
        render_dict = {}
        render_dict['HTML_URL_BASE'] = HTML_URL_BASE
        #render_dict['IS_ADMIN'] = is_user_admin(self.get_session().get_userid())
        render_dict['no_found_url'] = self.request.path
        self.render(no_found_file_path, **render_dict)


    @authenticated
    def process_get_and_post_request(self, req_method, *args, **kwargs):
        '''
        req_method: 'get' or 'post'
        format: /ug/users /ug/user/add /ug/user/edit /ug/user/del 
        as for /ug/user/add call html_ug_user_add(handler) and return dict
        '''
        logger.debug('DynamicPageHandler request.path    = %s'%self.request.path)
        logger.debug('DynamicPageHandler request method  = %s'%req_method)
        relative_url = self.request.path[len(URL_PREFIX + APP_PREFIX + '/pages'):].rstrip('/')
        relative_url_parts = relative_url.strip('/').split('/')
        local_file_path = os.path.join(LOCAL_HTML_BASE, *relative_url_parts).rstrip('/') + '.html'
        func_name = req_method + '_' + relative_url.strip('/').replace('/', '_')
        logger.debug('DynamicPageHandler func_name       = %s'%func_name)
        logger.debug('DynamicPageHandler relative_url    = %s'%relative_url)
        logger.debug('DynamicPageHandler local_file_path = %s'%local_file_path)
        render_dict = {}
        if hasattr(urlfunc, func_name):
            func_call = getattr(urlfunc, func_name)
            if type(func_call) == types.FunctionType:
                try:
                    logger.debug('DynamicPageHandler: call function(%s) in module urlfunc'%func_name)
                    render_dict = func_call(self)
                except Exception as ex:
                    logger.debug('DynamicPageHandler: exception during calling function(%s) in module urlfunc'%func_name)
                    return self.process_exception()
                if render_dict is None:
                    logger.debug('DynamicPageHandler: function(%s) in module urlfunc returned None'%func_name)
                    render_dict = {}
                else:
                    if render_dict.has_key('_redirect'):
                        logger.debug('DynamicPageHandler: rediect %s after call %s in urlfunc'%(render_dict['_redirect'], func_name))
                        return self.redirect(render_dict.pop('_redirect'))
            else:
                logger.debug('DynamicPageHandler: %s is not function in module urlfunc'%func_name)
        else:
            logger.debug('DynamicPageHandler: no attribute(%s) in module urlfunc'%func_name)
        if os.path.isfile(local_file_path):
            try:
                render_dict['HTML_URL_BASE'] = HTML_URL_BASE
                render_dict['IS_ADMIN'] = is_user_admin(self.get_session().get_userid())
                return self.render(local_file_path, **render_dict)
            except Exception as ex:
                return self.process_exception()
        else:
            #logger.debug('DynamicPageHandler: local HTML file not found :'+local_file_path)
            #return self.redirect(NOT_FOUND_URL)
            return self.process_no_found()


        '''
        if os.path.isfile(local_file_path):
            render_dict = {}
            if hasattr(urlfunc, func_name):
                func_call = getattr(urlfunc, func_name)
                if type(func_call) == types.FunctionType:
                    try:
                        render_dict = func_call(self)
                    except Exception as ex:
                        traceback.print_exc()
                        return self.redirect(ERROR_URL)
                    if render_dict is None:
                        logger.debug('DynamicPageHandler: function(%s) in module urlfunc returned None'%func_name)
                        render_dict = {}
                    elif render_dict.has_key('_redirect'):
                        return self.redirect(render_dict.pop('_redirect'))
                else:
                    logger.debug('DynamicPageHandler: %s is not function in module urlfunc'%func_name)
            else:
                logger.debug('DynamicPageHandler: no function in module urlfunc.%s'%func_name)
            render_dict['HTML_URL_BASE'] = HTML_URL_BASE
            try:
                #render html page
                return self.render(local_file_path, **render_dict)
            except Exception as ex:
                traceback.print_exc()
                return self.redirect(ERROR_URL)
        else:
            logger.debug('DynamicPageHandler: local HTML file not found')
            return self.redirect(NOT_FOUND_URL)


        if hasattr(urlfunc, func_name):
            the_func = getattr(urlfunc, func_name)
            if type(the_func) == types.FunctionType:
                logger.debug('DynamicPageHandler: call urlfunc.%s'%func_name)
                render_dict = the_func(self)
                if render_dict is None:
                    logger.debug('DynamicPageHandler: no returned dict in urlfunc.%s'%func_name)
                    render_dict = {}
                    #self.redirect(ERROR_URL)
                    #return
                if os.path.isfile(local_file_path):
                    render_dict['HTML_URL_BASE'] = HTML_URL_BASE
                    return self.render(local_file_path, **render_dict)
                else:
                    logger.debug('DynamicPageHandler: file not found %s'%local_file_path)
                    self.redirect(NOT_FOUND_URL)
                    return
            else:
                logger.debug('DynamicPageHandler: %s is not function'%the_func)
                self.redirect(ERROR_URL)
                return
        else:
            logger.debug('DynamicPageHandler: no attribute %s in urlfunc'%func_name)
            self.redirect(ERROR_URL)
            return
        '''


class LoginHandler(RequestHandlerEx):

    def get(self, *args, **kwargs):
        logger.debug('LoginHandler.get  request.path = %s'%self.request.path)
        next_url = self.get_argument('next', '')
        render_dict = {'HTML_URL_BASE':HTML_URL_BASE, 'next_url':next_url}
        login_html_path = os.path.join(LOCAL_HTML_BASE, 'login.html')
        self.render(login_html_path, **render_dict)


    def post(self, *args, **kwargs):
        logger.debug('LoginHandler.post request.path = %s'%self.request.path)
        username = self.get_argument('username', '')
        password = self.get_argument('password', '')
        next_url = self.get_argument('next_url', '')
        r = check_userpass(username, password)
        if r:
            logger.debug('authentication failed: '+r)
            login_html_path = os.path.join(LOCAL_HTML_BASE, 'login.html')
            render_dict = {'HTML_URL_BASE':HTML_URL_BASE, 'error':'error information'}
            self.render(login_html_path, **render_dict)
        else:
            user_id, user_name = get_login_user_info(username)
            self.get_session().set_user(user_id, user_name)
            if next_url:
                self.redirect(next_url)
            else:
                self.redirect(HOME_URL)


class LogoutHandler(RequestHandlerEx):

    def get(self, *args, **kwargs):
        logger.debug('LoginHandler.get  request.path = %s'%self.request.path)
        session.remove_session(self)
        self.redirect(LOGIN_URL)


'''
class ErrorHandler(RequestHandlerEx):

    def get(self, *args, **kwargs):
        logger.debug('ErrorHandler.get request.path = %s'%self.request.path)
        self.redirect(HOME_URL)
'''


class AjaxRequestHandler(RequestHandlerEx):

    #@tornado.web.authenticated
    def get(self, *args, **kwargs):
        logger.debug('AjaxRequestHandler.get  self.request.path =%s'%self.request.path)
        url = self.request.path[4:]
        if ajax.ajax_url_mapping.has_key(url):
            ajax.ajax_url_mapping[url][0](self, *args, **kwargs)
        else:
            self.write('{"status":"ERROR","cause":"url(%s) handler can not be found"}'%url)
            self.flush()        


    #@tornado.web.authenticated
    def post(self, *args, **kwargs):
        logger.debug('AjaxRequestHandler.post self.request.path =%s'%self.request.path)
        url = self.request.path[4:]
        if ajax.ajax_url_mapping.has_key(url):
            ajax.ajax_url_mapping[url][1](self, *args, **kwargs)
        else:
            self.write('{"status":"ERROR","cause":"url(%s) handler can not be found"}'%url)
            self.flush()        



class WebTerminalHandler(tornado.websocket.WebSocketHandler):
    pass


class TerminalPageHandler(RequestHandlerEx):
    pass


class WebSSHSizeHandler(RequestHandlerEx):
    pass